package com.crm.crm.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crm.crm.constant.CacheConstant;
import com.crm.crm.domain.SysDictData;
import com.crm.crm.domain.SysDictType;
import com.crm.crm.domain.dto.dict.DictDataDto;
import com.crm.crm.domain.dto.dict.DictTypeDto;
import com.crm.crm.domain.vo.dict.DictDataVo;
import com.crm.crm.domain.vo.dict.DictTypeVo;
import com.crm.crm.mapper.dict.DictMapper;
import com.crm.crm.mapper.dict.SysDictDataMapper;
import com.crm.crm.mapper.dict.SysDictTypeMapper;
import com.crm.crm.service.DictService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class DictServiceImpl implements DictService {
    @Autowired
    private DictMapper dictMapper;

    @Autowired
    private SysDictTypeMapper sysDictTypeMapper;

    @Autowired
    private SysDictDataMapper sysDictDataMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 根据字典类型查询字典数据
     *
     * @param dictType
     * @return
     */
    @Override
    public List<SysDictData> getDictData(String dictType) {
        Object redisReturn = redisTemplate.opsForValue().get(CacheConstant.DICT_DATA + dictType);
        if (redisReturn == null) {
            log.info("Redis中不存在字典{}的值，触发数据库查询", dictType);
            ArrayList<SysDictData> sysDictData = dictMapper.getDictData(dictType);
            redisTemplate.opsForValue().set(CacheConstant.DICT_DATA + dictType, JSONUtil.toJsonStr(sysDictData), 1, TimeUnit.HOURS);
            return sysDictData;
        } else {
            log.info("Redis中存在字典{}的值，直接返回", dictType);
            return JSONUtil.toList(JSONUtil.parseArray(redisReturn), SysDictData.class);
        }
    }

    /**
     * 查询字典类型列表
     *
     * @param dictTypeDto
     * @return
     */
    @Override
    public DictTypeVo getDictTypePage(DictTypeDto dictTypeDto) {
        // 初始化 params，防止 NullPointerException
        if (dictTypeDto.getParams() == null) {
            dictTypeDto.setParams(new HashMap<>());
        }

        String dictName = dictTypeDto.getDictName();
        String dictType = dictTypeDto.getDictType();
        String status = dictTypeDto.getStatus();
        String beginTime = dictTypeDto.getParams().get("beginTime");
        String endTime = dictTypeDto.getParams().get("endTime");

        LocalDate beginTimeDate = null;
        LocalDate endTimeDate = null;
        if (StrUtil.isNotEmpty(beginTime) && StrUtil.isNotEmpty(endTime)) {
            beginTimeDate = LocalDate.parse(beginTime);
            endTimeDate = LocalDate.parse(endTime);
        }

        Page<SysDictType> page = new Page<>(dictTypeDto.getPageNum(), dictTypeDto.getPageSize());
        LambdaQueryWrapper<SysDictType> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StrUtil.isNotEmpty(dictName), SysDictType::getDictName, dictName).like(StrUtil.isNotEmpty(dictType), SysDictType::getDictType, dictType).eq(StrUtil.isNotEmpty(status), SysDictType::getStatus, status).between(StrUtil.isNotEmpty(beginTime) && StrUtil.isNotEmpty(endTime), SysDictType::getCreateTime, beginTimeDate, endTimeDate);
        Page<SysDictType> sysDictTypePage = sysDictTypeMapper.selectPage(page, wrapper);

        return new DictTypeVo(sysDictTypePage.getTotal(), sysDictTypePage.getRecords());
    }

    /**
     * 新增字典类型
     *
     * @param sysDictType
     * @return
     */
    @Override
    public boolean addDictType(SysDictType sysDictType) {
        String dictName = sysDictType.getDictName();
        sysDictType.setCreateTime(LocalDateTime.now());

        try {
            sysDictTypeMapper.insert(sysDictType);
            log.info("新增字典类型：{}", dictName);
        } catch (Exception e) {
            log.info("新增字典类型失败：{}", e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 根据字典类型ID查询字典类型
     *
     * @param dictId
     * @return
     */
    @Override
    public SysDictType getDictTypeById(Long dictId) {
        LambdaQueryWrapper<SysDictType> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDictType::getDictId, dictId);
        SysDictType sysDictType = sysDictTypeMapper.selectOne(wrapper);
        return sysDictType;
    }

    /**
     * 查询字典类型列表
     *
     * @return
     */
    @Override
    public List<SysDictType> getDictTypeList() {
        List<SysDictType> sysDictTypes = sysDictTypeMapper.selectList(null);
        return sysDictTypes;
    }

    /**
     * 查询字典数据列表
     *
     * @param dictDataDto
     * @return
     */
    @Override
    public DictDataVo getDictDataList(DictDataDto dictDataDto) {
        String dictLabel = dictDataDto.getDictLabel();
        String dictType = dictDataDto.getDictType();
        String status = dictDataDto.getStatus();

        Page<SysDictData> page = new Page<>(dictDataDto.getPageNum(), dictDataDto.getPageSize());
        LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StrUtil.isNotEmpty(dictLabel), SysDictData::getDictLabel, dictLabel).eq(StrUtil.isNotEmpty(dictType), SysDictData::getDictType, dictType).eq(StrUtil.isNotEmpty(status), SysDictData::getStatus, status);
        Page<SysDictData> sysDictTypePage = sysDictDataMapper.selectPage(page, wrapper);

        return new DictDataVo(sysDictTypePage.getTotal(), sysDictTypePage.getRecords());
    }

    /**
     * 新增字典数据
     *
     * @param sysDictData
     * @return
     */
    @Override
    public boolean addDictData(SysDictData sysDictData) {
        String dictLabel = sysDictData.getDictLabel();
        sysDictData.setCreateTime(LocalDateTime.now());

        try {
            sysDictDataMapper.insert(sysDictData);
            log.info("新增字典类型：{}", dictLabel);
        } catch (Exception e) {
            log.info("新增字典类型失败：{}", e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 修改字典类型
     *
     * @param sysDictType
     * @return
     */
    @Override
    @Transactional
    public boolean updateDictType(SysDictType sysDictType) {
        String dictName = sysDictType.getDictName();
        String newDictType = sysDictType.getDictType();
        long dictId = sysDictType.getDictId();
        //先拿到修改前的字典类型
        String oleDictType = sysDictTypeMapper.selectOne(new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getDictId, dictId)).getDictType();
        //修改data表
        LambdaQueryWrapper<SysDictData> wrapperData = new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, oleDictType);
        List<SysDictData> sysDictDatum = sysDictDataMapper.selectList(wrapperData);
        //先删再存
        try {
            sysDictDataMapper.delete(wrapperData);
            for (SysDictData sysDictData : sysDictDatum) {
                sysDictData.setDictType(newDictType);
            }
            sysDictDataMapper.insert(sysDictDatum);
        } catch (Exception e) {
            log.info("修改数据字典失败：{}", e.getMessage());
            return false;
        }
        //修改type表
        try {
            LambdaQueryWrapper<SysDictType> wrapper = new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getDictId, dictId);
            sysDictTypeMapper.update(sysDictType, wrapper);
        } catch (Exception e) {
            log.info("修改字典类型失败：{}", e.getMessage());
            return false;
        }
        log.info("修改字典类型：{}", dictName);
        return true;
    }

    /**
     * 删除字典类型
     *
     * @param ids
     * @return
     */
    @Override
    @Transactional
    public boolean deleteDictType(String[] ids) {
        ArrayList<Long> idList = new ArrayList<>();
        for (String id : ids) {
            idList.add(Long.valueOf(id));
        }
        //先删data表
        //先拿字典类型名称
        ArrayList<String> toDeleteTypeList = new ArrayList<>();
        for (Long id : idList) {
            LambdaQueryWrapper<SysDictType> typeWrapper = new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getDictId, id);
            String dictType = sysDictTypeMapper.selectOne(typeWrapper).getDictType();
            //存到待删除字典类型list里
            toDeleteTypeList.add(dictType);
        }
        try {
            LambdaQueryWrapper<SysDictData> dataWrapper = new LambdaQueryWrapper<SysDictData>().in(SysDictData::getDictType, toDeleteTypeList);
            sysDictDataMapper.delete(dataWrapper);
        } catch (Exception e) {
            log.info("删除字典数据失败：{}", e.getMessage());
            return false;
        }
        //再删type表
        try {
            LambdaQueryWrapper<SysDictType> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(SysDictType::getDictId, idList);
            sysDictTypeMapper.delete(wrapper);
        } catch (Exception e) {
            log.info("删除字典类型失败：{}", e.getMessage());
            return false;
        }
        return true;
    }

    @Override
    public SysDictData getDictDataById(Long dictCode) {
        LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictCode, dictCode);
        SysDictData sysDictData = sysDictDataMapper.selectOne(wrapper);
        return sysDictData;
    }

    /**
     * 修改字典数据
     *
     * @param sysDictData
     * @return
     */
    @Override
    public boolean updateDictData(SysDictData sysDictData) {
        long dictCode = sysDictData.getDictCode();
        LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictCode, dictCode);
        try {
            sysDictDataMapper.update(sysDictData, wrapper);
        } catch (Exception e) {
            log.info("修改字典数据失败：{}", e.getMessage());
            return false;
        }
        return true;
    }

    @Override
    public boolean deleteDictData(String[] ids) {
        ArrayList<Long> idList = new ArrayList<>();
        for (String id : ids) {
            idList.add(Long.valueOf(id));
        }
        try {
            LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<SysDictData>().in(SysDictData::getDictCode, idList);
            sysDictDataMapper.delete(wrapper);
        } catch (Exception e) {
            log.info("删除字典数据失败：{}", e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 清空缓存
     *
     * @return
     */
    @Override
    public void clearCache() {
        log.info("开始清除字典缓存");
        String pattern = CacheConstant.DICT_DATA + "*";
        Set<String> keys = redisTemplate.keys(pattern);

        //遍历删除
        for (String key : keys) {
            redisTemplate.delete(key);
        }
    }
}
